/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package io.iec.edp.caf.msu.common;

import io.iec.edp.caf.common.JSONSerializer;
import io.iec.edp.caf.commons.runtime.CafEnvironment;

import io.iec.edp.caf.commons.utils.SpringBeanUtils;
import io.iec.edp.caf.msu.api.ServiceUnitAwareService;
import io.iec.edp.caf.msu.api.entity.CafMsuConfiguration;
import io.iec.edp.caf.msu.api.entity.DeploymentConfiguration;
import io.iec.edp.caf.msu.api.entity.ServiceUnitItem;

import io.iec.edp.caf.sumgr.api.IServiceUnitAware;
import io.iec.edp.caf.sumgr.api.entity.MsuType;
import io.iec.edp.caf.sumgr.api.entity.ServiceUnitInfo;
import lombok.extern.slf4j.Slf4j;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author Leon Huo
 * @Date: 2021/5/12
 */
@Slf4j
@Deprecated
//todo 被com.inspur.edp.dataie.rpc.client.DataIeRestServiceImpl依赖
public class ServiceUnitAwareImpl implements IServiceUnitAware {

    private Lock locker = new ReentrantLock();
    private Boolean initialized = false;
    private List<ServiceUnitInfo> infos;
    private List<String> serviceUnitNames;

    private static final ServiceUnitAwareService suService = SpringBeanUtils.getBean(ServiceUnitAwareService.class);

//    //单例模式 装载时完成初始化
//    private static ServiceUnitAwareUtil INSTANCE = new ServiceUnitAwareUtil();
//
//    /**
//     * 构造函数
//     */
//    private ServiceUnitAwareServiceImpl() {
//    }
//
//    /**
//     * 公有构造方法
//     *
//     * @return
//     */
//    public static ServiceUnitAwareUtil getInstance() {
//        return INSTANCE;
//    }

    /**
     * 当前Server中包含的所有的服务单元信息
     * @return
     */
    @Override
    public List<ServiceUnitInfo> getAllServiceUnits() {
//        this.ensureInitialized();
//        return this.infos;
        List<io.iec.edp.caf.msu.api.entity.ServiceUnitInfo> suInfos = suService.getAllServiceUnits();
        List<ServiceUnitInfo> result = new ArrayList<>();
        suInfos.forEach(info -> {
            ServiceUnitInfo newInfo = new ServiceUnitInfo();
            newInfo.setServiceUnitDes(info.getServiceUnitDes());
            newInfo.setApplicationName(info.getApplicationName());
            if(info.getMsuType().equals(io.iec.edp.caf.msu.api.enums.MsuType.Biz))
                newInfo.setMsuType(MsuType.Biz);
            else newInfo.setMsuType(MsuType.Common);
            newInfo.setName(info.getName());
            newInfo.setPath(info.getPath());
            newInfo.setType(info.getType());
            result.add(newInfo);
        });
        return result;
    }

    /**
     * 当前已启用的服务单元名称列表
     *
     * @return
     */
    @Override
    public List<String> getEnabledServiceUnits() {
//        this.ensureInitialized();
//        return this.serviceUnitNames;
        return suService.getEnabledServiceUnits();
    }

    /**
     * 保证已被初始化
     */
    private void ensureInitialized() {
        if (!this.initialized) {
            try {
                locker.lock();
                if (!this.initialized) {
                    //查找已安装的所有SU详情
                    this.infos = new ArrayList<>();

                    long startTime = System.currentTimeMillis();
                    //todo 这里不能用CafEnvironment.getServerRTPath()来获取path，因为在bean初始化之前就走了这个方法了，这个是后eviroment还没有
                    this.getServiceUnitInfo(this.infos, new File(CafEnvironment.getServerRTPath()));
                    //读取当前已启用的su配置列表
                    this.serviceUnitNames = this.readEnabledServiceUnits(this.infos);
                    log.info("enable service units: " + JSONSerializer.serialize(this.serviceUnitNames));
                    long endTime = System.currentTimeMillis();
                    if(log.isInfoEnabled()){
                        log.info("读取SU 程序运行时间：" + (endTime - startTime) + "ms");
                    }
//                    System.out.println("读取SU 程序运行时间：" + (endTime - startTime) + "ms");
                }
            } finally {
                this.initialized = true;
                locker.unlock();
            }
        }
    }

    /**
     * 递归获取服务单元信息
     *
     * @param infos
     * @param fileInfo
     */
    private void getServiceUnitInfo(List<ServiceUnitInfo> infos, File fileInfo) {
        if (fileInfo != null && fileInfo.exists() && fileInfo.isDirectory()) {
            File[] files = fileInfo.listFiles((dir, name) -> dir.isDirectory() && name != null && name.equalsIgnoreCase("ServiceUnit.json"));

            //识别为su目录
            if (files != null && files.length > 0) {
                File file = files[0];
                //读取serviceunit.json内容
                ServiceUnitInfo info = this.readServiceUnitInfo(this.readToBuffer(file.getAbsolutePath()));
                if (info != null) {
                    //更新applitionPath
                    info.setPath(fileInfo.getPath());
                    infos.add(info);
                }
            } else {
                //非su目录，继续递归，仅查找目录
                files = fileInfo.listFiles(pathname -> !pathname.isFile());
                if (files != null)
                    for (File file : files) {
                        getServiceUnitInfo(infos, file);
                    }
            }
        }
    }

    /**
     * 读取已启用的服务单元列表
     * 默认enabled = fasle 认为是禁用的，否则都认为是启用的
     */
    private List<String> readEnabledServiceUnits(List<ServiceUnitInfo> infos) {

        //todo CafEnvironment.getServerRTPath() 里用的eviroment在启动前还没有
        String suConfigPath = CafEnvironment.getServerRTPath() + File.separator + "config" +
                File.separator + "runtime" + File.separator + "caf_serviceunits.json";
        String content = this.readToBuffer(suConfigPath);

        //将所有识别到的su添加进来
        List<String> suNames = new ArrayList<>();
        infos.forEach(info -> suNames.add(info.getName()));
        //白名单用的空列表
        List<String> whiteNames = new ArrayList<>();

        DeploymentConfiguration deployConfig = JSONSerializer.deserialize(content, CafMsuConfiguration.class).getDeploymentConfiguration();

        for (ServiceUnitInfo suInfo : infos) {
            for (ServiceUnitItem suItem : deployConfig.getServiceUnits()) {
                if (suInfo.getName().equalsIgnoreCase(suItem.getName())) {
                    if (suItem.getEnabled()) {
                        whiteNames.add(suInfo.getName());
                    } else {
                        suNames.remove(suInfo.getName());
                    }
                }
            }
        }

        switch (deployConfig.getStrategy()) {
            case BlackList:
                return suNames;
            case WhiteList:
                return whiteNames;
        }

        return null;
    }

    /**
     * 将JSON字符串转换为对象
     *
     * @param content
     * @return
     */
    private ServiceUnitInfo readServiceUnitInfo(String content) {
        if (content == null || "".equals(content))
            return null;

        content = content.substring(content.indexOf(":") + 1, content.lastIndexOf("}"));
        ServiceUnitInfo info = JSONSerializer.deserialize(content, ServiceUnitInfo.class);
        if (info == null)
            return null;
        if ("Common".equalsIgnoreCase(info.getType()))
            info.setMsuType(MsuType.Common);
        else
            info.setMsuType(MsuType.Biz);
        return info;
    }

    /**
     * 读取文本文件内容
     *
     * @param filePath
     * @return
     * @throws IOException
     */
    private String readToBuffer(String filePath) {
        StringBuffer buffer = new StringBuffer();
        try {
            InputStream stream = null;
            BufferedReader reader = null;
            try {
                File file = new File(filePath);
                if (!file.exists())
                    return null;
                stream = new FileInputStream(file);
                String line; // 用来保存每行读取的内容
                reader = new BufferedReader(new InputStreamReader(stream, StandardCharsets.UTF_8));
                line = reader.readLine(); // 读取第一行
                while (line != null) { // 如果 line 为空说明读完了
                    buffer.append(line); // 将读到的内容添加到 buffer 中
                    buffer.append("\n"); // 添加换行符
                    line = reader.readLine(); // 读取下一行
                }
            } finally {
                if (reader != null)
                    reader.close();
                if (stream != null)
                    stream.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return buffer.toString();
    }
}
